package com.example.demo.randomdemo;

import com.example.demo.ServerIps;

/* ━━━━━━佛祖保佑━━━━━━
 *                  ,;,,;
 *                ,;;'(    社
 *      __      ,;;' ' \   会
 *   /'  '\'~~'~' \ /'\.)  主
 * ,;(      )    /  |.     义
 *,;' \    /-.,,(   ) \    码
 *     ) /       ) / )|    农
 *     ||        ||  \)
 *     (_\       (_\
 * ━━━━━━永无BUG━━━━━━
 * @author ：zjq
 * @date ：2021/3/2 16:27
 * @description: TODO    权重 + 轮询
 * @version: V1.0
 * @slogan: 天下风云出我辈，一入代码岁月催
 */
public class WeightRoundRobin {


    /**
     * 但是这种算法有一个缺点：一台服务器的权重特别大的时候，他需要连续的的处理请求，但是实际上我们想达到的效果是，
     * 对于100次请求，只要有100*8/50=16次就够了，这16次不一定要连续的访问，比如假设我们有三台服务器 servers = [A, B, C]，
     * 对应的权重为 weights = [5, 1, 1] , 总权重为7，那么上述这个算法的结果是：AAAAABC，那么如果能够是这么一个结果呢：
     * AABACAA，把B和C平均插入到5个A中间，这样是比较均衡的了。
     */

    private static Integer pos = 0;

    public static String getServer() {
        int totalWeight = 0;
        boolean sameWeight = true;
        // 如果所有权重都相等，那么随机一个ip就好了

        Object[] weights = ServerIps.WEIGHT_LIST.values().toArray();
        for (int i = 0; i < weights.length; i++) {
            Integer weight = (Integer) weights[i];
            totalWeight += weight;
            if (sameWeight && i > 0 && !weight.equals(weights[i - 1])) {
                sameWeight = false;
            }
        }
        Integer sequenceNum = Sequence.getAndIncrement();
        Integer offset = sequenceNum % totalWeight;
        offset = offset == 0 ? totalWeight : offset;
        if (!sameWeight) {
            for (String ip : ServerIps.WEIGHT_LIST.keySet()) {
                Integer weight = ServerIps.WEIGHT_LIST.get(ip);
                if (offset <= weight) {
                    return ip;
                }
                offset = offset - weight;
            }
        }
        String ip = null;
        synchronized (pos) {
            if (pos >= ServerIps.LIST.size()) {
                pos = 0;
            }
            ip = ServerIps.LIST.get(pos);
            pos++;
        }
        return ip;
    }

    public static void main(String[] args) {
        // 连续调用11次
        for (int i = 0; i < 11; i++) {
            System.out.println(getServer());
        }
    }


}

class Sequence {
    public static Integer num = 0;

    public static Integer getAndIncrement() {
        return ++num;
    }
}